/*
 * File     : StructureMethodsRecord.java
 * Created  : 13 Oct 2011
 *
 * Copyright © 2011 Matthew Wilson (mj. {my-surname} .uk {at} gmail.com)
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
package com.googlecode.dni.internal.structure;

import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;

import org.objectweb.asm.Type;

import com.googlecode.dni.library.Function;
import com.googlecode.dni.library.Library;
import com.googlecode.dni.type.nativetype.NativeTypes;
import com.googlecode.dni.type.structure.Structure;

/**
 * Encapsulates information about {@link Function}s on {@link Structure}s.
 *
 * @author Matthew Wilson
 */
public final class StructureMethodsRecord
{

    private final Class< ? extends Structure > structureType;

    private final Library library;

    private final List< Method > methods = new ArrayList< Method >();

    /**
     * @param structureType
     *            the owning structure type
     * @param library
     *            the library
     */
    StructureMethodsRecord( final Class< ? extends Structure > structureType,
                            final Library library )
    {
        this.structureType = structureType;
        this.library = library;
    }

    /**
     * @return the structureType
     */
    public Class< ? extends Structure > getStructureType()
    {
        return this.structureType;
    }

    /**
     * @return the library
     */
    public Library getLibrary()
    {
        return this.library;
    }

    /**
     * @return the methods
     */
    public List< Method > getMethods()
    {
        return this.methods;
    }

    /** {@inheritDoc} */
    @Override
    public String toString()
    {
        return "[" + this.library + " -> " + this.structureType.getName() + "]";
    }

    /**
     * Determines the method name to add to a library implementation for a
     * {@link Function}.
     *
     * @param method
     *            the method
     * @return the method name
     */
    public static String getStructureMethodName( final Method method )
    {
        return "_method_" + method.getName();
    }

    /**
     * Determines the method descriptor for a library implementation for a
     * {@link Function}.
     *
     * @param method
     *            the method
     * @return the method descriptor
     */
    public static String getStructureMethodDescriptor( final Method method )
    {
        // prepend the structure's type
        // e.g. interface S { float m( int i ); }
        //   => (JI)F
        String methodDescriptor = Type.getMethodDescriptor( method );
        assert methodDescriptor.charAt( 0 ) == '(';

        if ( NativeTypes.POINTER_SIZE == 8 )
        {
            return "(J" + methodDescriptor.substring( 1 );
        }

        assert NativeTypes.POINTER_SIZE == 4;
        return "(I" + methodDescriptor.substring( 1 );
    }

    /**
     * Adds a method.
     *
     * @param method
     *            the method
     */
    void addMethod( final Method method )
    {
        this.methods.add( method );
    }

}
